home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / arp.c < prev    next >
C/C++ Source or Header  |  1992-06-18  |  11KB  |  395 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "iface.h"
  8. #include "enet.h"
  9. #include "ax25.h"
  10. #include "arp.h"
  11. #ifdef    UNIX
  12. #include <memory.h>
  13. #endif
  14. static unsigned arp_hash();
  15. extern int32 ip_addr;        /* Our IP address */
  16.  
  17. /* ARP entries for particular subnetwork types. The table values
  18.  * are filled in by calls to arp_init() at device attach time
  19.  */
  20. static void arp_output();
  21.  
  22. #define    NTYPES    9
  23. struct arp_type arp_type[NTYPES];
  24.  
  25. /* Hash table headers */
  26. struct arp_tab *arp_tab[ARPSIZE];
  27.  
  28. struct arp_stat arp_stat;
  29.  
  30. /* Initialize an entry in the ARP table
  31.  * Called by the device driver at attach time
  32.  */
  33. arp_init(hwtype,hwalen,iptype,arptype,bdcst,format,scan)
  34. unsigned int hwtype;    /* ARP Hardware type */
  35. int hwalen;        /* Hardware address length */
  36. int iptype;        /* Subnet's protocol ID for IP */
  37. int arptype;        /* Subnet's protocol ID for ARP */
  38. char *bdcst;        /* Subnet's broadcast address (if any) */
  39. int (*format)();    /* Function to format hardware addresses */
  40. int (*scan)();        /* Function to scan addresses in ascii */    
  41. {
  42.     register struct arp_type *at;
  43.  
  44.     if(hwtype >= NTYPES)
  45.         return -1;    /* Table too small */
  46.  
  47.     at = &arp_type[hwtype];
  48.     at->hwalen = (int16)hwalen;
  49.     at->iptype = (int16)iptype;
  50.     at->arptype = (int16)arptype;
  51.     at->bdcst = bdcst;
  52.     at->format = format;
  53.     at->scan = scan;
  54.     return 0;
  55. }
  56.  
  57. /* Resolve an IP address to a hardware address; if not found,
  58.  * initiate query and return NULLCHAR.  If an address is returned, the
  59.  * interface driver may send the packet; if NULLCHAR is returned,
  60.  * res_arp() will have saved the packet on its pending queue,
  61.  * so no further action (like freeing the packet) is necessary.
  62.  */
  63. char *
  64. res_arp(interface,hardware,target,bp)
  65. struct interface *interface;    /* Pointer to interface block */
  66. int16 hardware;        /* Hardware type */
  67. int32 target;        /* Target IP address */
  68. struct mbuf *bp;    /* IP datagram to be queued if unresolved */
  69. {
  70.     void arp_output();
  71.     register struct arp_tab *arp;
  72.  
  73.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  74.         return arp->hw_addr;
  75.     /* Create an entry and put the datagram on the
  76.      * queue pending an answer
  77.      */
  78.     arp = arp_add(target,hardware,NULLCHAR,0,0);
  79.     enqueue(&arp->pending,bp);
  80.     arp_output(interface,hardware,target);
  81.     return NULLCHAR;
  82. }
  83. /* Handle incoming ARP packets. This is almost a direct implementation of
  84.  * the algorithm on page 5 of RFC 826, except for:
  85.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  86.  *    pending a reply to our ARP request.
  87.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  88.  * 3. Requests for IP addresses listed in our table as "published" are
  89.  *    responded to, even if the address is not our own.
  90.  */
  91. void
  92. arp_input(interface,bp)
  93. struct interface *interface;
  94. struct mbuf *bp;
  95. {
  96.     struct arp arp;
  97.     struct arp_tab *ap;
  98.     struct arp_type *at;
  99.     struct mbuf *htonarp();
  100.     
  101.     arp_stat.recv++;
  102.     if(ntoharp(&arp,&bp) == -1)    /* Convert into host format */
  103.         return;
  104.     if(arp.hardware >= NTYPES){
  105.         /* Unknown hardware type, ignore */
  106.         arp_stat.badtype++;
  107.         return;
  108.     }
  109.     at = &arp_type[arp.hardware];
  110.     if(arp.protocol != at->iptype){
  111.         /* Unsupported protocol type, ignore */
  112.         arp_stat.badtype++;
  113.         return;
  114.     }
  115.     if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  116.         /* Incorrect protocol addr length (different hw addr lengths
  117.          * are OK since AX.25 addresses can be of variable length)
  118.          */
  119.         arp_stat.badlen++;
  120.         return;
  121.     }
  122.     if(memcmp(arp.shwaddr,at->bdcst,(int)at->hwalen) == 0){
  123.         /* This guy is trying to say he's got the broadcast address! */
  124.         arp_stat.badaddr++;
  125.         return;
  126.     }
  127.     /* If this guy is already in the table, update its entry
  128.      * unless it's a manual entry (noted by the lack of a timer)
  129.      */
  130.     ap = NULLARP;    /* ap plays the role of merge_flag in the spec */
  131.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  132.      && ap->timer.start != 0){
  133.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  134.     }
  135.     /* See if we're the address they're looking for */
  136.     if(arp.tprotaddr == ip_addr){
  137.         if(ap == NULLARP)    /* Only if not already in the table */
  138.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  139.  
  140.         if(arp.opcode == ARP_REQUEST){
  141.             /* Swap sender's and target's (us) hardware and protocol
  142.              * fields, and send the packet back as a reply
  143.              */
  144.             memcpy(arp.thwaddr,arp.shwaddr,(int)uchar(arp.hwalen));
  145.             /* Mark the end of the sender's AX.25 address
  146.              * in case he didn't
  147.              */
  148.             if(arp.hardware == ARP_AX25)
  149.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  150.  
  151.             memcpy(arp.shwaddr,interface->hwaddr,(int)at->hwalen);
  152.             arp.tprotaddr = arp.sprotaddr;
  153.             arp.sprotaddr = ip_addr;
  154.             arp.opcode = ARP_REPLY;
  155.             if((bp = htonarp(&arp)) == NULLBUF)
  156.                 return;
  157.  
  158.             if(interface->forw != NULLIF)
  159.                 (*interface->forw->output)(interface->forw,
  160.                  arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  161.             else 
  162.                 (*interface->output)(interface,arp.thwaddr,
  163.                  interface->hwaddr,at->arptype,bp);
  164.             arp_stat.inreq++;
  165.         } else {
  166.             arp_stat.replies++;
  167.         }
  168.     } else if(arp.opcode == ARP_REQUEST
  169.         && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  170.         && ap->pub){
  171.         /* Otherwise, respond if the guy he's looking for is
  172.          * published in our table.
  173.          */
  174.         memcpy(arp.thwaddr,arp.shwaddr,(int)uchar(arp.hwalen));
  175.         /* Mark the end of the sender's AX.25 address
  176.          * in case he didn't
  177.          */
  178.         if(arp.hardware == ARP_AX25)
  179.             arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  180.         memcpy(arp.shwaddr,ap->hw_addr,(int)at->hwalen);
  181.         arp.tprotaddr = arp.sprotaddr;
  182.         arp.sprotaddr = ap->ip_addr;
  183.         arp.opcode = ARP_REPLY;
  184.         if((bp = htonarp(&arp)) == NULLBUF)
  185.             return;
  186.         if(interface->forw != NULLIF)
  187.             (*interface->forw->output)(interface->forw,
  188.              arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  189.         else 
  190.             (*interface->output)(interface,arp.thwaddr,
  191.              interface->hwaddr,at->arptype,bp);
  192.         arp_stat.inreq++;
  193.     }
  194. }
  195. /* Add an IP-addr / hardware-addr pair to the ARP table */
  196. struct arp_tab *
  197. arp_add(ipaddr,hardware,hw_addr,hw_alen,pub)
  198. int32 ipaddr;        /* IP address, host order */
  199. int16 hardware;        /* Hardware type */
  200. char *hw_addr;        /* Hardware address, if known; NULLCHAR otherwise */
  201. int16 hw_alen;        /* Length of hardware address */
  202. int pub;        /* Publish this entry? */
  203. {
  204.     void arp_drop();
  205.     int ip_route();
  206.     struct mbuf *bp,*dequeue();
  207.     register struct arp_tab *ap;
  208.     unsigned hashval,arp_hash();
  209.  
  210.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  211.         /* New entry */
  212.         if((ap = (struct arp_tab *)calloc(1,sizeof(struct arp_tab))) == NULLARP)
  213.             return NULLARP;
  214.         ap->timer.func = arp_drop;
  215.         ap->timer.arg = (char *)ap;
  216.         ap->hardware = hardware;
  217.         ap->ip_addr = ipaddr;
  218.  
  219.         /* Put on head of hash chain */
  220.         hashval = arp_hash(hardware,ipaddr);
  221.         ap->prev = NULLARP;
  222.         ap->next = arp_tab[hashval];
  223.         arp_tab[hashval] = ap;
  224.         if(ap->next != NULLARP){
  225.             ap->next->prev = ap;
  226.         }
  227.     }
  228.     if(hw_addr == NULLCHAR){
  229.         /* Await response */
  230.         ap->state = ARP_PENDING;
  231.         ap->timer.start = PENDTIME * (1000 / MSPTICK);
  232.     } else {
  233.         /* Response has come in, update entry and run through queue */
  234.         ap->state = ARP_VALID;
  235.         ap->timer.start = ARPLIFE * (1000 / MSPTICK);
  236.         if(ap->hw_addr != NULLCHAR)
  237.             free(ap->hw_addr);
  238.         if((ap->hw_addr = malloc(hw_alen)) == NULLCHAR){
  239.             free((char *)ap);
  240.             return NULLARP;
  241.         }
  242.         memcpy(ap->hw_addr,hw_addr,(int)hw_alen);
  243.         /* This kludge marks the end of an AX.25 address to allow
  244.          * for optional digipeaters (insert Joan Rivers salute here)
  245.          */
  246.         if(hardware == ARP_AX25)
  247.             ap->hw_addr[hw_alen-1] |= E;
  248.         ap->pub = pub;
  249.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  250.             ip_route(bp,0);
  251.     }
  252.     start_timer(&ap->timer);
  253.     return ap;
  254. }
  255.  
  256. /* Remove an entry from the ARP table */
  257. void
  258. arp_drop(ap)
  259. register struct arp_tab *ap;
  260. {
  261.     unsigned arp_hash();
  262.  
  263.     if(ap == NULLARP)
  264.         return;
  265.     stop_timer(&ap->timer);    /* Shouldn't be necessary */
  266.     if(ap->next != NULLARP)
  267.         ap->next->prev = ap->prev;
  268.     if(ap->prev != NULLARP)
  269.         ap->prev->next = ap->next;
  270.     else
  271.         arp_tab[arp_hash(ap->hardware,ap->ip_addr)] = ap->next;
  272.     if(ap->hw_addr != NULLCHAR)
  273.         free(ap->hw